package com.hjm.java.utils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 类复制属性工具
 */
public class ClassCopyUtil {

    public static <T, S> void copyProperties(T source, S target) {
        if (source == null || target == null) {
            throw new IllegalArgumentException("源对象和目标对象不能为空");
        }

        Class<?> sourceClass = source.getClass();
        Class<?> targetClass = target.getClass();

        for (Field sourceField : sourceClass.getDeclaredFields()) {
            try {
                sourceField.setAccessible(true);

                Field targetField = targetClass.getDeclaredField(sourceField.getName());
                if (targetField != null) {
                    targetField.setAccessible(true);

                    // 检查字段类型是否匹配或兼容
                    Class<?> sourceFieldType = sourceField.getType();
                    Class<?> targetFieldType = targetField.getType();

                    if (sourceFieldType.equals(targetFieldType)) {
                        // 如果字段类型相同，直接复制值
                        if (sourceFieldType.isPrimitive()) {
                            // 处理基本数据类型
                            copyPrimitiveValue(sourceField, source, targetField, target);
                        } else {
                            // 处理对象类型
                            copyObjectValue(sourceField, source, targetField, target);
                        }
                    } else if (targetFieldType.isAssignableFrom(sourceFieldType)) {
                        // 如果目标字段是源字段类型的父类，也可以复制（但这里不包括基本数据类型）
                        if (!sourceFieldType.isPrimitive()) {
                            copyObjectValue(sourceField, source, targetField, target);
                        } else {
                            throw new IllegalArgumentException("不兼容的字段类型: " + sourceField.getName());
                        }
                    }
                }
            } catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException |
                     InvocationTargetException e) {
                throw new RuntimeException("复制属性时出错", e);
            }
        }
    }

    private static void copyPrimitiveValue(Field sourceField, Object source, Field targetField, Object target)
            throws IllegalAccessException {
        if (sourceField.getType() == int.class) {
            targetField.setInt(target, sourceField.getInt(source));
        } else if (sourceField.getType() == boolean.class) {
            targetField.setBoolean(target, sourceField.getBoolean(source));
        } else if (sourceField.getType() == byte.class) {
            targetField.setByte(target, sourceField.getByte(source));
        } else if (sourceField.getType() == char.class) {
            targetField.setChar(target, sourceField.getChar(source));
        } else if (sourceField.getType() == short.class) {
            targetField.setShort(target, sourceField.getShort(source));
        } else if (sourceField.getType() == long.class) {
            targetField.setLong(target, sourceField.getLong(source));
        } else if (sourceField.getType() == float.class) {
            targetField.setFloat(target, sourceField.getFloat(source));
        } else if (sourceField.getType() == double.class) {
            targetField.setDouble(target, sourceField.getDouble(source));
        }
    }

    public static void copyObjectValue(Field sourceField, Object source, Field targetField, Object target)
            throws IllegalAccessException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
        // 确保sourceField和source是可访问的
        sourceField.setAccessible(true);

        // 获取源字段的值
        Object fieldValue = sourceField.get(source);
        if (fieldValue != null) {
            // 确保targetField是可访问的
            targetField.setAccessible(true);

            // 构造setter方法名
            String setterMethodName = "set" + capitalize(targetField.getName());

            // 获取目标对象的setter方法
            Class<?> targetType = target.getClass();
            Method setterMethod = targetType.getMethod(setterMethodName, targetField.getType());

            // 调用setter方法设置值
            setterMethod.invoke(target, fieldValue);
        }
    }

    private static String capitalize(String name) {
        if (name == null || name.isEmpty()) {
            return name;
        }
        return name.substring(0, 1).toUpperCase() + name.substring(1);
    }
}

